
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>mybtis #{}和${}的区别 - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>mybtis #{}和${}的区别 - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">在MyBatis中，#{} 和 ${} 在处理SQL参数时的根本区别是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">#{} 是参数预处理方式，它会将SQL中的参数表示为占位符，并使用PreparedStatement进行参数的安全赋值，能有效防止SQL注入。而 ${} 是字符串替换方式，它会直接将参数的字符串值拼接到SQL语句中，存在SQL注入的风险。</div>
          </div>
          <div class="card-source">来源: 区别</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">为什么说使用 #{} 可以提高SQL的安全性？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">因为 #{} 采用参数预处理机制。MyBatis会将 #{} 中的参数值进行预处理和转义，然后作为PreparedStatement的参数传递给数据库，而不是直接作为SQL命令的一部分执行。这可以有效防止SQL注入攻击。</div>
          </div>
          <div class="card-source">来源: #{} 参数预处理方式</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">在MyBatis中使用 ${} 主要会带来什么安全风险？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">使用 ${} 的主要风险是SQL注入攻击。因为它不会对参数进行预处理或转义，而是直接将参数的字符串值拼接到SQL语句中。如果参数值来自外部输入，攻击者可能通过构造恶意字符串来改变SQL的原始逻辑，从而执行非法操作。</div>
          </div>
          <div class="card-source">来源: ${} 参数字符串替换方式</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">当MyBatis处理一个包含`#{id}`的查询时，实际发送到数据库的SQL语句结构是怎样的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">当MyBatis处理`select * from t_User where id = #{id}`时，它会生成一个Prepared Statement，其SQL结构为 `select * from t_User where id = ?`。参数值会通过安全的方式绑定到这个问号占位符上。</div>
          </div>
          <div class="card-source">来源: #{} 参数预处理方式</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">如果一个参数`id`的值是`1`，那么MyBatis如何处理SQL语句`select * from t_User where id = ${id}`？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">MyBatis会直接进行字符串替换，将`${id}`替换为参数`id`的值`1`。最终生成的SQL语句是`select * from t_User where id = 1`。这个过程没有预处理和转义。</div>
          </div>
          <div class="card-source">来源: ${} 参数字符串替换方式</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">尽管 #{} 更安全，但在什么特定场景下我们仍然需要使用 ${}？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">在需要动态改变SQL结构本身而不是参数值的场景下，需要使用 ${}。例如，当需要根据传入的参数动态指定查询的表名或列名时，就必须使用 ${} 进行字符串替换。</div>
          </div>
          <div class="card-source">来源: 区别</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
